home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpat2-1.000 / xpat2-1 / xpat2-1.04 / src / Xv-main.c < prev   
C/C++ Source or Header  |  1995-11-25  |  18KB  |  584 lines

  1. /*****************************************************************************/
  2. /*                                         */
  3. /*                                         */
  4. /*    X patience version 2 -- module Xv-main.c                 */
  5. /*                                         */
  6. /*    main function for the Xview interface                     */
  7. /*    written by Brandon S. Allbery                         */
  8. /*    based on code by Heiko Eissfeldt and Michael Bischoff             */
  9. /*    see COPYRIGHT.xpat2 for Copyright details                 */
  10. /*                                         */
  11. /*                                         */
  12. /*****************************************************************************/
  13.  
  14. #ifdef useXview
  15.  
  16. #undef ONLINE_HELP    /* not supported yet */
  17.  
  18. #include "X-pat.h"
  19. #include "version.h"
  20. #include "pat.bm"
  21.  
  22. Window table;
  23. Frame mainwindow;
  24. Panel buttonbox;
  25. Canvas canvas;
  26. Menu cmenu;
  27. Event *bp_event;
  28.  
  29. static int audio = 1;
  30. static Xv_Notice confirm_dialog;
  31. static Panel_item sound_button;
  32. static void (*execfunc)(void);
  33.  
  34. #define C_TABLE CMS_CONTROL_COLORS + 0
  35. #define C_WHITE CMS_CONTROL_COLORS + 1
  36. #define C_RED CMS_CONTROL_COLORS + 2
  37. #define C_BACK CMS_CONTROL_COLORS + 3
  38. #define C_ARROW CMS_CONTROL_COLORS + 4
  39. #define C_MARK CMS_CONTROL_COLORS + 5
  40. #define C_BLACK    CMS_CONTROL_COLORS + 6
  41.  
  42. int
  43. checksound(void)
  44. {
  45.     return audio;
  46. }
  47.  
  48. void
  49. cmd_LeavePat(void)
  50. {
  51.     play_sound("goodbye");
  52.     xv_destroy_safe(mainwindow);
  53. }
  54.  
  55. void cmd_Confirm(void) {
  56.     if (execfunc) {
  57.     void (*execfunc2)(void) = execfunc;    /* erase it first! */
  58.     execfunc = NULL;
  59.     /* XtPopdown(popup); */
  60.     (*execfunc2)();    /* finally execute the desired function */
  61.     }
  62. }
  63. void cmd_Cancel(void) {
  64.     if (execfunc) {
  65.     execfunc = NULL;
  66.     /* XtPopdown(popup); */
  67.     }
  68. }
  69.  
  70. static void
  71. confirm_action(Xv_Notice notice, int value, Event ev)
  72. {
  73.     if (value == NOTICE_YES)
  74.     (*execfunc)();
  75.     execfunc = 0;
  76. }
  77.  
  78. void
  79. request_confirm(void (*dofunc)(void), const char *prompt)
  80. {
  81.     if (execfunc)
  82.     return;
  83.     execfunc = dofunc;
  84.     xv_set(confirm_dialog,
  85.        NOTICE_MESSAGE_STRING, prompt,
  86.        XV_SHOW, TRUE,
  87.        0);
  88. }
  89.  
  90. static void
  91. set_sound(Xv_Notice notice, Event ev)
  92. {
  93.     audio = !audio;
  94.     xv_set(sound_button,
  95.        PANEL_LABEL_STRING, (audio? "Quiet": "Sound"),
  96.        0);
  97. }
  98.  
  99. static void
  100. selectrules(Menu mnu, Menu_item mi)
  101. {
  102.     change_rules((char *) xv_get(mi, MENU_STRING));
  103. }
  104.  
  105. static const char *
  106. d_mk_name(const char *owner, const char *name)
  107. {
  108.     static char buf[128];
  109.  
  110.     strcpy(buf, owner);
  111.     strcat(buf, ".");
  112.     strcat(buf, name);
  113.     return buf;
  114. }
  115.  
  116. static const char *
  117. d_get_string(const char *cmd, const char *res, const char *dft)
  118. {
  119.     char cbuf[128], Cbuf[128];
  120.  
  121.     strcpy(cbuf, d_mk_name(cmd, res));
  122.     strcpy(Cbuf, d_mk_name("XPat", res));
  123.     return defaults_get_string(cbuf, Cbuf, (char *) dft);
  124. }
  125.  
  126. static int
  127. d_get_number(const char *cmd, const char *res, const char *dftv, int minv,
  128.          int maxv)
  129. {
  130.     char cbuf[128], Cbuf[128];
  131.     int dft;
  132.  
  133.     if (dftv && *dftv)
  134.     dft = atoi(dftv);
  135.     else
  136.     dft = -1;
  137.     strcpy(cbuf, d_mk_name(cmd, res));
  138.     strcpy(Cbuf, d_mk_name("XPat", res));
  139.     return defaults_get_integer_check(cbuf, Cbuf, dft, minv, maxv);
  140. }
  141.  
  142. static void
  143. usage(const char *arg)
  144. {
  145.     fprintf(stderr, "usage: pat [options] [<seed> or <savedgame>]\n");
  146.     fprintf(stderr, "valid options are XView options ans:\n");
  147. #ifdef LOADCARDS
  148.     fprintf(stderr, "-cards <cardset>        set cardset to external file\n");
  149. #endif
  150.     fprintf(stderr, "-xpmdir <directory>     for internal cardset: load xpm files\n");
  151.     fprintf(stderr, "-sound <0/1>            enables/disables sound\n");
  152.  
  153.     fprintf(stderr, "-tb <backgroundcolor>   set background color of tableau\n");
  154.     fprintf(stderr, "-cb <cardbackcolor>     set cardback color\n");
  155.     fprintf(stderr, "-markcolor <markcolor>  set color of card marks\n");
  156.     fprintf(stderr, "-markwidth <markwidth>  set width of card marks\n");
  157.     fprintf(stderr, "-gapx, -gapy            set space between cards (0 to 20)\n");
  158.     fprintf(stderr, "\ngame customization:\n");
  159.     fprintf(stderr, "-rules <ruleset>        set rules to HM or Spider or Stairs\n");
  160.     fprintf(stderr, "-slots <slots>          set number of slots (2 to 60)\n");
  161.     fprintf(stderr, "-decks <decks>          set number of decks (1 to 9)\n");
  162.     fprintf(stderr, "-tmps <tmps>            set number of tmps (1 to 9)\n");
  163.     fprintf(stderr, "-faceup <faceup>        set initial deal parameter (0 to 20)\n");
  164.     fprintf(stderr, "-facedown <facedown>    set initial deal parameter (0 to 20)\n");
  165.     fprintf(stderr, "-jokers <jokers>        set number of jokers (do not use, it's too easy)\n");
  166.     fprintf(stderr, "-flips <flips>          limit number of flips (0 to 99)\n");
  167.     fprintf(stderr, "-relaxed 0|1            choose easy or hard variant\n");
  168.     fprintf(stderr, "-turn <turn>            set number of cards to turn (1 to 9)\n");
  169.     fprintf(stderr, "-rotations <num>        set maximum number of slot rotations (0 to 9)\n");
  170.     fprintf(stderr, "-p{0,1,2,3} <param>     set various rule parameters\n");
  171. #if 0    /* for insiders only */
  172.     fprintf(stderr, "-autolayout <0/1>       0: to avoid automatic re-layout at resize time\n");
  173.     fprintf(stderr, "-mem <0/1>              0: do not store card images at full depth internally\n");
  174.     fprintf(stderr, "-cround <cornersize>    set size of round card corners (0 to 20)\n");
  175. #endif
  176.     if (arg)
  177.      fprintf(stderr,"argument \"%s\" caused this message\n", arg);
  178.     exit(EXIT_FAILURE);
  179. }
  180.  
  181. /* enum { String, Number, Bool } argtype; */
  182. #define String 0
  183. #define Number 1
  184.  
  185. int
  186. main(int argc, char **argv)
  187. {
  188.     int i;
  189.     long seed = -1L;
  190.     const char *restoregame = NULL;
  191.     XColor pixels[CMS_CONTROL_COLORS + 7];
  192.     Cms cms;
  193.     Server_image icon_map;
  194.     Icon pat_icon;
  195.     Menu mnu;
  196.     static const char *cmdname;
  197.  
  198.     /* these must be static, since their address is taken */
  199.     static int slots, faceup, facedown, decks, p0, p1, p2, p3; /* rules customization */
  200.     static int linewidth, cround, gapx, gapy, autolayout, mem;
  201.     static int tmps, arrw, arrh, jokers, bx, by, sound = 1;
  202.     static const char *ruleset, *cbcolor, *bkcolor = "DarkKhaki";
  203.     static const char *cardset = NULL, *markcolor, *xpmdir;
  204.     static const char *arrowcolor;
  205.  
  206. static struct option {
  207.     const char *option;
  208.     const char *resource;
  209.     const char *value;
  210.     void *where;
  211.     int type;
  212.     int minval;       /* only for Number */
  213.     int maxval;       /* only for Number */
  214.     const char *cmdarg;
  215. } options[] = {
  216.     /* first option must be -rules */
  217.     { "-rules",        "Rules",         "Gypsy",     &ruleset,   String },
  218.     { "-autolayout","AutoLayout",    "1",         &autolayout,Number,  0,  1 },
  219.     { "-mem",       "Mem",           "1",         &mem,       Number,  0,  1 },
  220.     { "-xpmdir",    "XpmDir",        NULL,        &xpmdir,    String },
  221. #ifdef LOADCARDS
  222.     { "-cards",     "Cards",         NULL,        &cardset,   String },
  223. #endif
  224.     { "-slots",     "Slots",         NULL,        &slots,     Number, -1, MAXPILES },
  225.     { "-relaxed",   "relaxed",         NULL,        &p0,        Number, -1,  9 },
  226.     { "-flips",     "flips",         NULL,        &p1,        Number, -1, 99 },
  227.     { "-turn",      "turn",         NULL,        &p2,        Number, -1,  9 },
  228.     { "-rotations", "rotations",     NULL,        &p3,        Number, -1,  9 },
  229.     { "-decks",     "Decks",         NULL,        &decks,     Number, -1,  9 },
  230.     { "-tmps",      "Tmps",          NULL,        &tmps,      Number, -1, 16 },
  231.     { "-faceup",    "Faceup",        NULL,        &faceup,    Number, -1, 16 },
  232.     { "-facedown",  "Facedown",      NULL,        &facedown,  Number, -1, 16 },
  233.     { "-jokers",    "Jokers",          NULL,        &jokers,    Number, -1, 16 },
  234.     { "-cround",    "CardRound",     NULL,        &cround,    Number, -1, 99 },
  235.     { "-sound",     "Sound",         "1",         &sound,     Number,  0,  1 },
  236.     { "-bx",        "ButtonGapX",    "4",         &bx,        Number,  0, 99 },
  237.     { "-by",        "ButtonGapY",    "4",         &by,        Number,  0, 99 },
  238.     { "-aw",        "ArrowWidth",    NULL,        &arrw,      Number, -1, 30 },
  239.     { "-ah",        "ArrowHeight",   NULL,        &arrh,      Number, -1, 30 },
  240.     { "-gapx",      "GapX",          "4",         &gapx,      Number,  0, 99 },
  241.     { "-gapy",      "GapY",          "4",         &gapy,      Number,  0, 99 },
  242.     { "-cb",        "CardbackColor", "SlateGrey", &cbcolor,   String },
  243.     { "-tb",           "TableColor",    "LightSlateGrey", &bkcolor,   String },
  244.     { "-markcolor", "MarkColor",     "black",        &markcolor, String },
  245.     { "-markwidth", "MarkWidth",     "999",       &linewidth, Number,  1,999 },
  246.     { "-arrowcolor","ArrowColor",    "Gold",      &arrowcolor,String },
  247. };
  248. #define NUMOPTIONS      (sizeof(options) / sizeof(options[0]) - 1)
  249.  
  250.     xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);
  251.  
  252.     for (i = 0; i <= NUMOPTIONS; i++)
  253.         options[i].cmdarg = NULL;
  254.  
  255.     if ((cmdname = strrchr(argv[0], '/')))
  256.     ++cmdname;
  257.     else
  258.     cmdname = argv[0];
  259.     if (strncmp(cmdname, "xpat", 4))
  260.     options[0].cmdarg = cmdname;
  261.  
  262.     for (i = 1; i < argc - 1; i++)    /* merge command line options */
  263.     {
  264.     int j;
  265.  
  266.     if (*argv[i] != '-')
  267.         break;
  268.     for (j = 0; j <= NUMOPTIONS; j++)
  269.     {
  270.         if (strcmp(argv[i], options[j].option) == 0)
  271.         {
  272.         /* should range-check it */
  273.         options[j].cmdarg = argv[++i];
  274.         break;
  275.         }
  276.         }
  277.         if (j > NUMOPTIONS)
  278.         usage(argv[i]);
  279.     }
  280.     if (i < argc)        /* seed or savegame left */
  281.     {
  282.     if (i != argc - 1)
  283.         usage(argv[i]);
  284.     if (isdigit(*argv[i]))
  285.     {
  286.         seed = atol(argv[i]);
  287.         if (seed < 0L || seed >= 1000000000L)
  288.         usage(argv[i]);
  289.     }
  290.     else if (*argv[i] != '-')
  291.         restoregame = argv[i];
  292.     else
  293.         usage(argv[i]);
  294.     }
  295.  
  296.     /*
  297.      * XView doesn't automatically use the resource database.  The next
  298.      * step after getting this working is to add XV_INSTANCE_NAME and
  299.      * XV_USE_DB entries such that resources are automatically used.
  300.      *
  301.      * One problem here is that I don't think I can get away with just
  302.      * passing a background color a' la Xlib/Xt.  :-(
  303.      */
  304.     for (i = 0; i <= NUMOPTIONS; i++)    /* get resources from server */
  305.     {
  306.     switch (options[i].type)
  307.     {
  308.     case String:
  309.         *((const char **) options[i].where) =
  310.         (options[i].cmdarg? options[i].cmdarg:
  311.          d_get_string(cmdname, options[i].resource, options[i].value));
  312.         break;
  313.     case Number:
  314.         *((int *) options[i].where) =
  315.         (options[i].cmdarg? atoi(options[i].cmdarg):
  316.          d_get_number(cmdname, options[i].resource,
  317.                   options[i].value, options[i].minval,
  318.                   options[i].maxval));
  319.         break;
  320.     }
  321.     }
  322.  
  323.     if (!sound)
  324.     audio = 0;
  325.  
  326.     if (restoregame &&
  327.     (decks != -1 || slots != -1 || faceup != -1 || facedown != -1))
  328.     fprintf(stderr, "warning: customization parameters are ignored\n");
  329.  
  330.     {
  331.     const char *s;
  332.  
  333.     langdir = (s = getenv("LANG")) ? s : "";
  334.     }
  335.     read_message_file("messages");
  336.     read_keyboard_file("keys");
  337.  
  338.     graphics_control(Disable);
  339.     if (restoregame)
  340.         load_game(restoregame);
  341.     else
  342.     {
  343.     new_rules(ruleset, decks, slots, faceup, facedown, jokers, tmps, p0,
  344.           p1, p2, p3);
  345.     newgame(seed);
  346.     }
  347.  
  348.     dpy = (Display *) xv_get(xv_default_server, XV_DISPLAY);
  349.     screen = DefaultScreen(dpy);
  350.     graphic.is_color = (DisplayCells(dpy, screen) > 2);
  351.     init_gfx();
  352.     if (!graphic.is_color)
  353.     {
  354.     cms = 0;
  355.     pixels[C_ARROW].pixel = whitepixel;
  356.     pixels[C_WHITE].pixel = whitepixel;
  357.     pixels[C_RED].pixel = blackpixel;
  358.     pixels[C_BACK].pixel = blackpixel;
  359.     pixels[C_TABLE].pixel = blackpixel;
  360.     pixels[C_MARK].pixel = blackpixel;
  361.     pixels[C_BLACK].pixel = blackpixel;
  362.     }
  363.     else
  364.     {
  365.     cms = (Cms) xv_create(0, CMS,
  366.                   CMS_SIZE, CMS_CONTROL_COLORS + 7,
  367.                   CMS_CONTROL_CMS, TRUE,
  368.                   CMS_NAMED_COLORS,
  369.                           bkcolor, "white", "Red3", cbcolor,
  370.                       arrowcolor, markcolor, "black", 0,
  371.                   0);
  372.     xv_get(cms, CMS_X_COLORS, pixels);
  373.     }
  374.     
  375.     init_cards(cardset, cround, cround, pixels[C_RED].pixel,
  376.            pixels[C_BACK].pixel, mem, xpmdir);
  377.  
  378.     graphic.xgap = (XSize_t) gapx;
  379.     graphic.ygap = (XSize_t) gapy;
  380.     graphic.autolayout = autolayout;
  381.     /* compute minimum size needed */
  382.     generic_minwindow((XSize_t *) &graphic.min_width,
  383.               (XSize_t *) &graphic.min_height);
  384.     graphic.width = graphic.min_width;
  385.     graphic.height = graphic.min_height;
  386.     mainwindow = (Frame) xv_create(0, FRAME,
  387.                    XV_INSTANCE_NAME, "xpat",
  388. #if 0
  389.                    FRAME_LABEL, cmdname,
  390. #endif
  391.                    FRAME_LABEL,
  392.                        (rules.longname? rules.longname:
  393.                             rules.shortname),
  394.                    FRAME_SHOW_HEADER, TRUE,
  395.                    FRAME_SHOW_FOOTER, TRUE,
  396.                    FRAME_LEFT_FOOTER, "",
  397.                    FRAME_RIGHT_FOOTER, "",
  398.                    FRAME_WM_COMMAND_ARGC_ARGV, argc, argv,
  399.                    0);
  400.     icon_map = (Server_image) xv_create(0, SERVER_IMAGE,
  401.                     XV_WIDTH, pat_width,
  402.                     XV_HEIGHT, pat_height,
  403.                     SERVER_IMAGE_X_BITS, pat_bits,
  404.                     0);
  405.     pat_icon = (Icon) xv_create(mainwindow, ICON,
  406.                 ICON_IMAGE, icon_map,
  407.                 0);
  408.     xv_set(mainwindow, FRAME_ICON, pat_icon, 0);
  409.     init_mark(pixels[C_MARK].pixel, linewidth);
  410.     init_arrow(pixels[C_ARROW].pixel, arrw, arrh);
  411.  
  412.     buttonbox = (Panel) xv_create(mainwindow, PANEL,
  413.                   XV_INSTANCE_NAME, "buttonpanel",
  414.                   PANEL_ITEM_X_GAP, bx,
  415.                   PANEL_ITEM_Y_GAP, by,
  416.                   0);
  417.     mnu = (Menu) xv_create(0, MENU,
  418.                MENU_GEN_PIN_WINDOW, mainwindow, "Game",
  419.                MENU_ACTION_ITEM, "Drop Bookmark", cmd_DropBookmark,
  420.                MENU_ACTION_ITEM, "Goto Bookmark", cmd_GotoBookmark,
  421.                MENU_ACTION_ITEM, "Replay", cmd_ReplayGame,
  422.                MENU_ACTION_ITEM, "Restart", cmd_RestartGame,
  423.                MENU_ACTION_ITEM, "New Game", rq_AnotherGame,
  424.                MENU_ACTION_ITEM, "Quit", rq_LeavePat,
  425.                0);
  426.     xv_create(buttonbox, PANEL_BUTTON,
  427.           XV_INSTANCE_NAME, "game",
  428.           PANEL_LABEL_STRING, "Game",
  429.           PANEL_ITEM_MENU, mnu,
  430.           0);
  431.     cmenu = (Menu) xv_create(0, MENU,
  432.                  MENU_GEN_PIN_WINDOW, mainwindow, "XPat",
  433.                  MENU_TITLE_ITEM, "XPat",
  434.                  MENU_ACTION_ITEM, "New Game", rq_AnotherGame,
  435.                  MENU_ACTION_ITEM, "Bookmark", cmd_DropBookmark,
  436.                  MENU_ACTION_ITEM, "Deal", cmd_DealCards,
  437.                  MENU_ACTION_ITEM, "Stack", cmd_ToStack,
  438.                  0);
  439.     mnu = (Menu) xv_create(0, MENU,
  440.                MENU_GEN_PIN_WINDOW, mainwindow, "Rules",
  441.                0);
  442.     {
  443.     extern struct rules *rulepool[];
  444.     struct rules **rp;
  445.     Menu_item mi;
  446.  
  447.     for (rp = rulepool; *rp; rp++)
  448.     {
  449.         mi = (Menu_item) xv_create(0, MENUITEM,
  450.                        MENU_STRING, (*rp)->shortname,
  451.                        MENU_NOTIFY_PROC, selectrules,
  452.                        MENU_RELEASE,
  453.                        0);
  454.         xv_set(mnu, MENU_APPEND_ITEM, mi, 0);
  455.     }
  456.     }
  457.     xv_create(buttonbox, PANEL_BUTTON,
  458.           XV_INSTANCE_NAME, "rules",
  459.           PANEL_LABEL_STRING, "Rules",
  460.           PANEL_ITEM_MENU, mnu,
  461.           0);
  462.     
  463.     xv_create(buttonbox, PANEL_BUTTON,
  464.           XV_INSTANCE_NAME, "cards",
  465.           PANEL_LABEL_STRING, "Cards",
  466.           PANEL_NOTIFY_PROC, cmd_DealCards,
  467.           0);
  468.     xv_create(buttonbox, PANEL_BUTTON,
  469.           XV_INSTANCE_NAME, "undo",
  470.           PANEL_LABEL_STRING, "Undo",
  471.           PANEL_NOTIFY_PROC, cmd_UndoMove,
  472.           0);
  473.     xv_create(buttonbox, PANEL_BUTTON,
  474.           XV_INSTANCE_NAME, "redo",
  475.           PANEL_LABEL_STRING, "Redo",
  476.           PANEL_NOTIFY_PROC, cmd_RedoMove,
  477.           0);
  478.     xv_create(buttonbox, PANEL_BUTTON,
  479.           XV_INSTANCE_NAME, "score",
  480.           PANEL_LABEL_STRING, "Score",
  481.           PANEL_NOTIFY_PROC, cmd_ShowScore,
  482.           0);
  483.     xv_create(buttonbox, PANEL_BUTTON,
  484.           XV_INSTANCE_NAME, "hint",
  485.           PANEL_LABEL_STRING, "Hint",
  486.           PANEL_NOTIFY_PROC, cmd_NextHint,
  487.           0);
  488.     xv_create(buttonbox, PANEL_BUTTON,
  489.           XV_INSTANCE_NAME, "stack",
  490.           PANEL_LABEL_STRING, "Move to Stack",
  491.           PANEL_NOTIFY_PROC, cmd_ToStack,
  492.           0);
  493. #ifdef ONLINE_HELP
  494.     /* should be a window button... */
  495.     /* The Help window contains a Textsw and a "Topics" menubutton. */
  496.     xv_create(buttonbox, PANEL_BUTTON,
  497.           XV_INSTANCE_NAME, "help",
  498.           PANEL_LABEL_STRING, "Help...",
  499.           PANEL_NOTIFY_PROC, popup_help,
  500.           0);
  501. #endif
  502.     xv_create(buttonbox, PANEL_BUTTON,
  503.           XV_INSTANCE_NAME, "save",
  504.           PANEL_LABEL_STRING, "Save",
  505.           PANEL_NOTIFY_PROC, cmd_SaveGame,
  506.           0);
  507. #ifdef SOUND
  508. #if 0
  509.     /* this is ugly.  UGLY! */
  510.     xv_create(buttonbox, PANEL_TOGGLE,
  511.           XV_INSTANCE_NAME, "sound",
  512.           PANEL_LABEL_STRING, "",
  513.           PANEL_CHOOSE_ONE, FALSE,
  514.           PANEL_CHOICE_STRINGS,
  515.               "Sound",
  516.               0,
  517.           PANEL_VALUE, sound,
  518.           PANEL_NOTIFY_PROC, set_sound,
  519.           0);
  520. #endif
  521.     sound_button = xv_create(buttonbox, PANEL_BUTTON,
  522.                  XV_INSTANCE_NAME, "sound",
  523.                  PANEL_LABEL_STRING, (audio? "Quiet": "Sound"),
  524.                  PANEL_NOTIFY_PROC, set_sound,
  525.                  0);
  526. #endif
  527.     window_fit(buttonbox);
  528.  
  529.     confirm_dialog = (Xv_Notice) xv_create(mainwindow, NOTICE,
  530.                        XV_INSTANCE_NAME, "prompt",
  531.                        NOTICE_NO_BEEPING, TRUE,
  532.                        NOTICE_BUTTON_YES, "Yes",
  533.                        NOTICE_BUTTON_NO, "No",
  534.                        NOTICE_EVENT_PROC, confirm_action,
  535.                        0);
  536.  
  537.     /* frame size forwarding fails when borders are on */
  538.     canvas = (Canvas) xv_create(mainwindow, CANVAS,
  539.                 XV_INSTANCE_NAME, "desktop",
  540.                 CANVAS_MIN_PAINT_WIDTH, graphic.min_width,
  541.                 CANVAS_MIN_PAINT_HEIGHT, graphic.min_height,
  542.                 CANVAS_WIDTH, graphic.min_width,
  543.                 CANVAS_HEIGHT, graphic.min_height,
  544.                 CANVAS_RESIZE_PROC, table_resize,
  545.                 CANVAS_REPAINT_PROC, table_repaint,
  546.                 WIN_BELOW, buttonbox,
  547.                 XV_X, 0,
  548.                 0);
  549.     xv_set(canvas_paint_window(canvas),
  550.        WIN_EVENT_PROC, table_events,
  551.        WIN_CONSUME_EVENTS,
  552.            WIN_ASCII_EVENTS, WIN_MOUSE_BUTTONS, 0,
  553.        WIN_CONSUME_X_EVENT_MASK, Button3MotionMask,
  554.        (cms? WIN_CMS: 0), cms,
  555.        WIN_BACKGROUND_COLOR, C_TABLE,
  556.        0);
  557.     table = (Window) xv_get(canvas_paint_window(canvas), XV_XID);
  558.     frame_pack_all(mainwindow);
  559.  
  560.     graphics_control(Enable);
  561.     init_layout();            /* position the piles in a nice way */
  562.     for (i = 0; i < game.numpiles; ++i)
  563.     pile_resize(i);
  564.     show_message(TXT_WELCOME, VERSION);
  565.     xv_main_loop(mainwindow);
  566.     return 0;
  567. }
  568.  
  569. void
  570. show_message(const char *fmt, ...)
  571. {
  572.     static char msg[512];
  573.     va_list args;
  574.  
  575.     if (!fmt)
  576.     return;
  577.     va_start(args, fmt);
  578.     vsprintf(msg, fmt, args);
  579.     va_end(args);
  580.     xv_set(mainwindow, FRAME_LEFT_FOOTER, msg, 0);
  581. }
  582.  
  583. #endif
  584.